package com.nifostasky.main.reflex.newInstance;

/**
 * 通过反射入口对象(class对象),创建实例
 * 1. 通过`Class.newInstance()`直接创建对象。
 * 2. 通过Class实例获取到`Constructor`（构造器），通过构造器创建对象。
 */

import lombok.SneakyThrows;
import org.hibernate.validator.internal.util.privilegedactions.NewInstance;

import java.lang.reflect.Constructor;
import java.util.Arrays;

/**
 * | 返回值             | 方法说明                                                     |
 * | :----------------- | :----------------------------------------------------------- |
 * | `Constructor`      | `getConstructor(Class<?>... parameterTypes)` 返回一个 `Constructor` 对象，它反映此 `Class` 对象所表示的类的public构造方法。 |
 * | `Constructor<?>[]` | `getConstructors()` 返回所有 `Constructor` 对象，它反映此 `Class` 对象所表示的类的public构造方法。 |
 * | `Constructor`      | `getDeclaredConstructor(Class<?>... parameterTypes)` 返回一个 `Constructor` 对象，该对象反映此 `Class` 对象所表示的类的public/private构造方法。 |
 * | `Constructor<?>[]` | `getDeclaredConstructors()` 返回所有 `Constructor` 对象，该对象反映此 `Class` 对象所表示的类的public/private构造方法。 |
 */
public class InstanceClass {
    /**
     * 1. 通过`Class.newInstance()`直接创建对象。
     * 一般就用这个方法创建对象就行了;
     *  这是调用无参构造方法进行创建对象
     */
    @SneakyThrows
    public static Object createObjectByNewInstance(){
        //获取反射入口对象(Class对象)
        String classpath = "com.nifostasky.main.reflex.template.Student";
        Class<?> aClass = Class.forName(classpath);
        //创建对象(未知类型)
        Object object = aClass.newInstance();
        return object;
    }

    /**
     * 2. 通过Class实例获取到`Constructor`（构造器），通过构造器创建对象。
     */
    @SneakyThrows
    public static Object createObjectByConstructor(){
        //获取反射入口对象(Class对象)
        String classpath = "com.nifostasky.main.reflex.template.Student";
        Class<?> aClass = Class.forName(classpath);
        // 创建对象(未知类型)
        Constructor<?> constructor = aClass.getConstructor();
        Object object = constructor.newInstance();
        Constructor<?> constructor1 = aClass.getConstructor(String.class);
        Object object1 = constructor1.newInstance("nihao");
        // 如果构造器为private，则可以设置访问权限为true，即可newInstance
        constructor.setAccessible(true);
        Object privateObject = constructor.newInstance();
        return object1;
    }

    /**
     * 3. `Constructor`（构造器），研究
     */
    @SneakyThrows
    public static void researchConstructor(){
        //获取反射入口对象(Class对象)
        String classpath = "com.nifostasky.main.reflex.template.Student";
        Class<?> aClass = Class.forName(classpath);
        //获取所有的constructor
        System.out.println("-----------------------通过参数类型获取指定的构造方法(public)----------------------------------------------");
        Constructor<?> constructor = aClass.getConstructor(String.class);
        System.out.println(constructor.toString());
        System.out.println("---------------------------------------------------------------------");

        System.out.println("-----------------------获取全部构造方法(public)----------------------------------------------");
        Constructor<?>[] constructors = aClass.getConstructors();
        Arrays.asList(constructors).stream().forEach(i -> System.out.println(i.toString()));
        System.out.println("---------------------------------------------------------------------");

        System.out.println("-----------------------获取全部构造方法(public/private)----------------------------------------------");
        Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
        Arrays.asList(declaredConstructors).stream().forEach(i -> System.out.println(i.toString()));
        System.out.println("---------------------------------------------------------------------");

        System.out.println("-----------------------通过参数类型获取指定的构造方法----------------------------------------------");
        Constructor<?> declaredAnnotation = aClass.getDeclaredConstructor(String.class,Integer.class,Boolean.class);
        System.out.println(declaredAnnotation.toString());
    }

    public static void main(String[] args) {
//        InstanceClass.researchConstructor();
        Object object1 = InstanceClass.createObjectByNewInstance();
        Object object2 = InstanceClass.createObjectByConstructor();
        System.out.println(object1.toString() +"\n"+object2.toString());
    }
}
